package game.metalmax.module.world
{
	/**
	 * WorldManager.as
	 * Yin Hao
	 * @version 1.0.0
	 * 
	 * Description.
	 * 
	 * Copyright (c) 2012 Yin Hao
	 * 
	 * Permission is hereby granted, free of charge, to any person obtaining a copy
	 * of this software and associated documentation files (the "Software"), to deal
	 * in the Software without restriction, including without limitation the rights
	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	 * copies of the Software, and to permit persons to whom the Software is
	 * furnished to do so, subject to the following conditions:
	 * 
	 * The above copyright notice and this permission notice shall be included in
	 * all copies or substantial portions of the Software.
	 * 
	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	 * THE SOFTWARE.
	 */
	
	import game.metalmax.animation.CharacterSOB;
	import game.metalmax.animation.NpcSOB;
	import game.metalmax.animation.TankSOB;
	import game.metalmax.animation.zone.SceneZone;
	import game.metalmax.config.GameConfig;
	import game.metalmax.controller.Notifications;
	import game.metalmax.entity.character.Character;
	import game.metalmax.entity.main.Dialog;
	import game.metalmax.events.MetalMaxEvent;
	import game.metalmax.module.character.CharacterManager;
	
	import showtime.framework.core.pattern.Singleton;
	import showtime.framework.engine.World2D;
	import showtime.framework.engine.map.MapEventType;
	import showtime.framework.engine.map.MapObjectType;
	import showtime.framework.engine.map.rpg.ObjectHolder;
	import showtime.framework.events.MessageDispatcher;
	import showtime.framework.manager.DataBaseManager;
	import showtime.framework.mvc.patterns.facade.Facade;
	import showtime.framework.object.Item;

	public class WorldManager extends Singleton
	{
		private var objectStack:Vector.<Object> = null;
		
		public var lastAccessCharacterSOB:CharacterSOB = null;		
			
		public var nowMapID:String = null;
		
		public var nowThemeID:String = null;
		
		public static function getInstance():WorldManager
		{
			return WorldManager(Singleton.getInstanceOrCreate(WorldManager));
		}
		
		override protected function initialize():void
		{
			super.initialize();
			
			objectStack = new Vector.<Object>();
		}
		
		public function registerBoxes():void
		{
			
		}
		
		
		public function addObject(object:Object):void
		{
			objectStack.push(object);
		}
		
		public function restoreObjects():void
		{
			for each (var object:Object in objectStack)
			{
				object.visible = true;
			}
			
			objectStack.length = 0;
		}
		
		public function restoreLastAccessCharacterSOBStatus():void
		{
			if (lastAccessCharacterSOB != null)
			{
				lastAccessCharacterSOB.play(lastAccessCharacterSOB.getLastAnimationName());
				lastAccessCharacterSOB.active = true;
			} 
		}
		
		/**
		 * Open box in the scene of the world,And also send packet to server.
		 *  
		 * @param box
		 * 
		 */		
		public function openBox(box:Object):void
		{
			if (box.source.animationName == "CLOSE")
			{
				box.play("OPEN", true);
				WorldProxy(Facade.getInstance().retrieveProxy(String(WorldProxy))).actionItemC2S(box.source);	
			}
			
		}
		
		public function transferTank():void
		{
			var target:CharacterSOB = SceneZone(World2D.scene).target;

			while (target != null)
			{				
				if (Character(target.source).vehicle != null)
				{										
					MessageDispatcher.getInstance().dispatchEvent(new MetalMaxEvent(MetalMaxEvent.TRANSFER_OFF_TANK, target));
				}
				else
				{
					var objects:Array = SceneZone(World2D.scene).map.getObjectsByPoint(target.getNowPoint());
					
					for each (var object:Object in objects)
					{
						if (object is TankSOB && object != target)
						{
							MessageDispatcher.getInstance().dispatchEvent(new MetalMaxEvent(MetalMaxEvent.TRANSFER_ON_TANK, {tank:object, hero:target}));
							SceneZone(World2D.scene).map.removeObject(TankSOB(object));
							break;
						}
					}
					
				}	
				
				target = target.followTarget;
			}		
		}
		
		public function preHandleEvent(event:ObjectHolder):void
		{
			switch (event.type)
			{
				case MapEventType.DOOR:
				{
					var object:Object = SceneZone(World2D.scene).map.getObjectByID(event.properties["objectID"]);					
					object.visible = false;
					
					WorldManager.getInstance().addObject(object);
					break;
				}
			}
		}
		
		public function postHandleEvent(event:ObjectHolder):void
		{
			switch (event.type)
			{
				case MapEventType.TRANSFER:
				{
					handleTransferEvent(event);
					break;
				}
				case MapEventType.SCRIPT:
				{	
					handleScriptEvent(event);
					break;
				}
				case MapEventType.DOOR:
				{
					handleDoorEvent(event);				
					break;
				}
				case MapEventType.DETECTOR:
				{
					handleDetectorEvent(event)
					break;
				}
					
			}
		}
		
		public function preHandleObject(object:Object):void
		{
			
		}

		public function postHandleObject(object:Object):void
		{
			if (object == null)
			{
				return;
			}		
			
			switch (object.source.type)
			{
				case MapObjectType.NPC:
				{
					object.active = false;
					WorldManager.getInstance().lastAccessCharacterSOB = CharacterSOB(object);	
					if (CharacterSOB(object).getAnimationName() != SceneZone(World2D.scene).target.getOppositeAnimationName())
					{
						CharacterSOB(object).play(SceneZone(World2D.scene).target.getOppositeAnimationName());	
					}			
					
					var dialog:Dialog = DataBaseManager.getInstance().read(Dialog, Character(object.source).dialogID);	
					dialog.reset();
					
					Facade.getInstance().sendNotification(Notifications.OPEN_DIALOG_WINDOW, dialog);
					break;
				}
				case MapObjectType.ITEM:
				{
					switch (object.source.subType)
					{
						case Item.BOX:
						{
							openBox(object);
							break;
						}
					}
					
				}
			}
		
		}
		
		
		
		//////////////////////////////////////
		//			Inner Functions         //
		//////////////////////////////////////
		private function handleDoorEvent(event:ObjectHolder):void
		{
			var object:Object = SceneZone(World2D.scene).map.getObjectByID(event.properties["objectID"]);					
			object.visible = false;
			
			WorldManager.getInstance().addObject(object);
		}
		
		private function handleDetectorEvent(event:ObjectHolder):void
		{
			var object:Object = SceneZone(World2D.scene).map.getObjectByPoint(SceneZone(World2D.scene).target.getDectectorPoint());
			
			if (object != null)
			{
				if (object is NpcSOB)
				{
					postHandleObject(object);
				}
			}
		}
		
		private function handleTransferEvent(event:ObjectHolder):void
		{
			var spawnPoint:Array = event.properties["spawnPoint"].split(",");
			
			WorldManager.getInstance().nowMapID = event.properties["mapID"];			
			
			CharacterManager.getInstance().self.spawnPoint.x = spawnPoint[0] * GameConfig.MAP_TILE_WIDTH;
			CharacterManager.getInstance().self.spawnPoint.y = spawnPoint[1] * GameConfig.MAP_TILE_HEIGHT;
			
			Facade.getInstance().sendNotification(Notifications.ENTER_SCENE);
			
			WorldProxy(Facade.getInstance().retrieveProxy(String(WorldProxy))).moveHeroC2S(CharacterManager.getInstance().self.spawnPoint.x, CharacterManager.getInstance().self.spawnPoint.y);
		}
		
		private function handleScriptEvent(evt:ObjectHolder):void
		{
			var scriptType:int = evt.properties["scriptType"];
			var scriptID:int = evt.properties["scriptID"];
			switch (scriptType)
			{
				case 2:
				{
					var dialog:Dialog = DataBaseManager.getInstance().read(Dialog, scriptID);	
					dialog.reset();
					Facade.getInstance().sendNotification(Notifications.OPEN_DIALOG_WINDOW, dialog);
					break;
				}
			}
		}
		
	}
}